`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date: 2021/11/23 00:41:49
// Design Name: 
// Module Name: uart_rx
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: RX_DONE可以提前，但不能滞后，可能会影响后续数据进入
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////


module uart_rx(
           input clk,
           input rstn,
           input uart_rx_in,
           input[2:0] Baudrate_Set,//波特率输�?
           output reg [7:0] uart_rx_Data,
           output Rx_Done//高电平：可以接收数据；低电平：正在接收数�?
    );

    //高电平计数reg，line131
    reg[2:0] data_r[7:0];//二维寄存�?,数据高电平累加器，以下都�?
    reg [2:0] sta_bit;
    reg [2:0] end_bit;



    reg[1:0] edge_check;//1:前一时刻电平//后一时刻电平，若前为1，后�?0，可能为起始�?
    wire nedge_check;
    //边缘�?测判断起始位
    always @(posedge clk ) begin
        edge_check[0] <=uart_rx_in;//后一时刻电平
        edge_check[1] <= edge_check[0];//前一时刻电平
    end
    assign nedge_check = (edge_check == 2'b10)?1:0;//下降沿检�?

    //抗干扰，把每1位数据分为16段（sample_cnt），去掉前5端后4端，取中7段进行采样
    //波特率为Baudrate,有：每一段时间：1_000_000_000 / Baudrate / 16
    //每一位的1/16为计数周:
    //在每1位的小段中间采样
    reg [15:0] Bps_DR;
    wire bps_clk_16x; //
    reg [8:0] div_cnt;
    always @( *) begin
        case (Baudrate_Set)
            0:Bps_DR <= (1_000_000_000 / 9600 / 16 /20) - 1 ;
            1:Bps_DR <= (1_000_000_000 / 4800 / 16 /20 ) - 1;
            2:Bps_DR <= (1_000_000_000 / 38400 / 16 /20)  - 1;
            3:Bps_DR <= (1_000_000_000 / 57600 / 16 /20  )- 1;
            4:Bps_DR <= (1_000_000_000 / 115200 / 16 /20 )- 1 ;
            default : Bps_DR <= (1_000_000_000 / 9600 / 16 /20 )- 1 ;
        endcase        
    end
    assign bps_clk_16x = (div_cnt == Bps_DR /2 );//每一段的开始，产生的一个时钟脉冲信号

    //使能divcnt计数产生信号
    reg RX_EN ;

    always @(posedge clk or negedge rstn) begin
        if (!rstn) begin
            RX_EN <= 1'b0;
        end
        else begin
            if (nedge_check) begin
                RX_EN <= 1'b1;
            end
            else begin
                if (Rx_Done || (sta_bit >= 4)) begin //如果接收完毕，或者起始位并不�?0的话，RX_EN拉低，不进行接收使能
                    RX_EN <= 1'b0;
                end
            end
        end
    end


    

    always @(posedge clk or negedge rstn) begin
        if (!rstn) begin
            div_cnt <= 9'd0;
        end
        else //�?测到下降沿开始计时
            if (RX_EN) begin
                if (div_cnt == Bps_DR) begin//以115200的波特率为例。为26时归0，重新计数，在13（中间时）时，bps_clk_16x拉高
                        div_cnt <= 9'd0;
                end
                else begin
                    div_cnt <= div_cnt + 1'b1;//
                end
            end
        
        else begin
            div_cnt <= 9'd0;
        end
    end

    //采样数据
    reg[14:0] sample_cnt;//采样计数。//bps_cnt
    always @(posedge clk or negedge rstn) begin
        if (!rstn) begin
            sample_cnt <= 15'd0;
        end
        else begin
            if(RX_EN)begin
                if (bps_clk_16x) begin//当采样时钟高电平�?
                    if (sample_cnt == 160) begin//160 是每一次送入的1字节信息的总计数长度，10位数据，每位分个16段
                            sample_cnt <= 15'd0;
                    end
                    else begin
                        sample_cnt <= sample_cnt + 1'b1;
                    end
                end
                else begin
                    sample_cnt <= sample_cnt ;
                end
            end
            else begin
                sample_cnt <= 0;
            end
        end
    end

    //接收数据，统计高电平出现的数�?
    //reg[2:0] data_r[9:0];//二维寄存�?,数据高电平累加器，以下都�?
    //reg [2:0] sta_bit;
    //reg [2:0] end_bit;
    always @(posedge clk or negedge rstn) begin
        if (!rstn) begin
            sta_bit <= 3'd0;
            end_bit <= 3'd0;
            data_r[0] <= 3'd0;
            data_r[1] <= 3'd0;
            data_r[2] <= 3'd0;
            data_r[3] <= 3'd0;
            data_r[4] <= 3'd0;
            data_r[5] <= 3'd0;
            data_r[6] <= 3'd0;
            data_r[7] <= 3'd0;
        end
        else begin
            if (bps_clk_16x) begin //每个数据，中间5~14段统计高电平数量，判断接收信号的电平。
                case (sample_cnt)
                    0:begin //清零
                                    sta_bit <= 3'd0;
                                    end_bit <= 3'd0;
                                    data_r[0] <= 3'd0;
                                    data_r[1] <= 3'd0;
                                    data_r[2] <= 3'd0;
                                    data_r[3] <= 3'd0;
                                    data_r[4] <= 3'd0;
                                    data_r[5] <= 3'd0;
                                    data_r[6] <= 3'd0;
                                    data_r[7] <= 3'd0;
                    end
                    //0~4不操作,取中间的段进行电平累加，下面为5~14段的各个中间值
                    5,6,7,8,9,10,11: sta_bit <= sta_bit + uart_rx_in;//起始位计数器
                    21,22,23,24,25,26,27:data_r[0] <= data_r[0] + uart_rx_in ;
                    37,38,39,40,41,42,43:data_r[1] <= data_r[1] +uart_rx_in;
                    53,54,55,56,57,58,59:data_r[2] <= data_r[2] +uart_rx_in;
                    69,70,71,72,73,74,75:data_r[3] <= data_r[3] +uart_rx_in;
                    85,86,87,88,89,90,91:data_r[4] <= data_r[4] +uart_rx_in;
                    101,102,103,104,105,106,107:data_r[5] <= data_r[5] +uart_rx_in;
                    117,118,119,120,121,122,123:data_r[6] <= data_r[6] +uart_rx_in;
                    133,134,135,136,137,138,139:data_r[7] <= data_r[7] +uart_rx_in;
                    149,150,151,152,153,154,155:end_bit <= end_bit +uart_rx_in;
                    default : ;//其他情况啥都不做
                        
                endcase
            end

        end
    end

    
    always @(posedge clk or negedge rstn) begin
        if (!rstn) begin
            uart_rx_Data <= 0;
        end
        else begin
            if (bps_clk_16x  && (sample_cnt == 159)) begin //必须是159，160无法记到，所以数据为0
                uart_rx_Data[0] <= (data_r[0] >= 4)? 1'b1 : 1'b0 ;
                uart_rx_Data[1] <= (data_r[1 ] >= 4)? 1'b1 : 1'b0 ;
                uart_rx_Data[2] <= (data_r[2] >= 4)? 1'b1 : 1'b0 ;
                uart_rx_Data[3] <= (data_r[3] >= 4)? 1'b1 : 1'b0 ;
                uart_rx_Data[4] <= (data_r[4] >= 4)? 1'b1 : 1'b0 ;
                uart_rx_Data[5] <= (data_r[5] >= 4)? 1'b1 : 1'b0 ;
                uart_rx_Data[6] <= (data_r[6] >= 4)? 1'b1 : 1'b0 ;
                uart_rx_Data[7] <= (data_r[7] >= 4)? 1'b1 : 1'b0 ;
            end
        end
    end
    
    //creat rx_ready
    reg Rx_Done_Reg ;
    always @(posedge clk or negedge rstn) begin
        if (!rstn) begin
            Rx_Done_Reg <= 1'b0;
        end
        else begin
            if ((div_cnt == Bps_DR / 2) && (sample_cnt == 160)) begin
                Rx_Done_Reg <= 1'b1;
            end
            else begin
                Rx_Done_Reg <= 1'b0;
            end
        end
    end
    assign Rx_Done = Rx_Done_Reg;
    
endmodule
